#ifndef LS_SyncQueue_HPP
#define LS_SyncQueue_HPP

#include <queue>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <iostream>
#include <optional>

using namespace std;

template <typename T>
class SyncQueue
{
public:
    SyncQueue(int maxSize) : m_maxSize(maxSize), m_needStop(false) {

    }

    ~SyncQueue() {
        stop();
    }

    bool get_needStop() {
        return m_needStop;
    }

    void put(const T &x)
    {
        add(x);
    }

    void put(T &&x)
    {
        add(std::forward<T>(x));
    }

    /// @note 取出整个队列
    // void take(std::queue<T> &queue)
    // {
    //     std::unique_lock<std::mutex> locker(m_mutex);
    //     m_notEmpty.wait(locker, [this]
    //                     { return m_needStop || notEmpty(); });

    //     if (m_needStop)
    //         return;
    //     queue = std::move(m_queue); ///< 移动语义
    //     m_notFull.notify_one();
    // }

    std::optional<T> take()
    {
        std::unique_lock<std::mutex> locker(m_mutex);
        m_notEmpty.wait(locker, [this]
                        { return m_needStop || notEmpty(); });
        
        if (m_needStop)
            return {};
        
        T t = m_queue.front();
        m_queue.pop();
        m_notFull.notify_one();
        return t;
    }

    /// @note 中断入队或者出队
    void stop()
    {
        {
            std::lock_guard<std::mutex> locker(m_mutex);
            m_needStop = true;
        }
        m_notFull.notify_all();
        m_notEmpty.notify_all();
    }

    bool empty()
    {
        std::lock_guard<std::mutex> locker(m_mutex);
        return m_queue.empty();
    }

    bool full()
    {
        std::lock_guard<std::mutex> locker(m_mutex);
        return m_queue.size() == m_maxSize;
    }

    size_t size()
    {
        std::lock_guard<std::mutex> locker(m_mutex);
        return m_queue.size();
    }

    /// @note 没有加锁
    int count()
    {
        return m_queue.size();
    }

private:
    /// @note 判断队列是否不满
    /// 这里之所以没有加锁，是因为调用外部已经加锁
    bool notFull() const
    {
        bool full = m_queue.size() >= m_maxSize;
        if (full)
            cout << "full, waiting，thread id: " << this_thread::get_id() << endl;
        return !full;
    }

    /// @note 判断队列是否不为空
    /// 这里之所以没有加锁，是因为调用外部已经加锁
    bool notEmpty() const
    {
        bool empty = m_queue.empty();
        if (empty)
            cout << "empty,waiting，thread id: " << this_thread::get_id() << endl;
        return !empty;
    }

    /// @note 模板函数（注意命名区别于 T）
    template <typename F>
    void add(F &&x)
    {
        std::unique_lock<std::mutex> locker(m_mutex);
        /// @note 如果 STOP 或者队列不满则不用阻塞
        m_notFull.wait(locker, [this]
                       { return m_needStop || notFull(); });
        if (m_needStop)
            return;

        m_queue.push(std::forward<F>(x)); ///< 入队
        m_notEmpty.notify_one(); ///< 通知队列不为空
    }

private:
    std::queue<T> m_queue;               ///< 缓存队列
    std::mutex m_mutex;                 ///< 互斥量和条件变量结合起来使用
    std::condition_variable m_notEmpty; ///< 不为空的条件变量
    std::condition_variable m_notFull;  ///< 没有满的条件变量
    int m_maxSize;                      ///< 同步队列最大的 size

    bool m_needStop;                    ///< 停止的标志
};



#endif